#! /usr/bin/perl

#this perl script will allow a new user to enter his/her information and will appropriately handle both correct and incorrect input and ultimately direct the user to the appropriate main site

#use the HMTLSubs package and ValidationSubs package as well as the database
use HTMLSubs;
use ValidationSubs;
use DBQueries;
use CGI;

#use the MD5 package
use Digest::MD5 qw(md5 md5_hex md5_base64);


#also enable strict mode
use strict;

#start by determining if any information was passed to the script so that the proper actions can be taken
#obtain the input 
my $input = obtain_input();


#if input is of length 0, proceed by displaying the login page
if(length($input) == 0){
	
	#call subroutine to display the full login/welcome page
	display_registration();
}

#otherwise proceed to decompose the submission from the user and adding him/her to the database
else{
	
	#call method to split the full string into a hash of individual variables
	#this subroutine returns a reference to the submitted info hash
	my $ref_submitted_info = HTMLSubs->decode_input($input);
	
	#now call subroutine to process input
	#pass this sub the reference to submitted info
	#this subroutine will take control of the flow of the script and determine what actions to further take
	process_registration($ref_submitted_info);
	
}

#subroutine to both determine the validity of the users input and to process all data
#this subroutine will call a subroutine to determine if each of the data fields was entered correctly
#each of those decisions will be stored in a "boolean" variable so the script can then notify the user of all errors individually
sub process_registration{
	
	#obtain user information from parameter
	my $ref_user_info = $_[0];
	
	#dereference hash to local variable
	my %user_info = %$ref_user_info;
	
	#declare boolean variables
	my ($validFName, $validLName, $validUserName, $validEmail, $validPwords);
	
	#call subroutines to determine each validtiy
	$validFName = ValidationSubs->validate_name($user_info{'firstName'});
	$validLName = ValidationSubs->validate_name($user_info{'lastName'});
	$validUserName = ValidationSubs->validate_user($user_info{'username'});
	$validEmail = ValidationSubs->validate_email($user_info{'email'});
	$validPwords = ValidationSubs->validate_passwords($user_info{'password1'}, $user_info{'password2'});
	
	#now ensure that all information was correct
	if($validFName == 1 && $validLName == 1 && $validUserName == 1 && $validEmail == 1 && $validPwords ==1){
		
		#md5 the password so that it is securely stored
		my $hashed_password = md5_hex($user_info{'password1'});
		
		#call subroutine to add information to database
		DBQueries::addUser($user_info{'username'}, $user_info{'firstName'}, $user_info{'lastName'}, $user_info{'email'}, $hashed_password);
		
		#call subroutine to email user to confirm registration
		send_confirmation($ref_user_info);
		
		#add information to the database
		add_information_to_db($user_info{'username'});
		
		#call subroutine to show success screen (this screen will take the user to the main menu)
		show_success($user_info{'username'});
	}
	
	#otherwise show submission screen again with proper error messages
	else{
		
		#declare hash to store individual error messages associated with individual incorrect inpus
		my %errors;
		
		#declare hash to store any potential valid inputs to ease re-submission
		my %correct;
		
		#now go through each submission and add error messages or correct values
		#first name
		if($validFName == 1){
			
			#add value to correct and blank to error
			$correct{'firstName'} = $user_info{'firstName'};
			$errors{'firstName'} = "";
		}
		else{
			
			#add blank to correct and message to error
			$correct{'firstName'} = "";
			$errors{'firstName'} = "<tr><td></td><td><font color=\"red\" size=\"2\">Invalid First Name Given</font></td></tr>";
		}
		
		#last name
		if($validLName == 1){
			
			#add value to correct and blank to error
			$correct{'lastName'} = $user_info{'lastName'};
			$errors{'lastName'} = "";
		}
		else{
			
			#add blank to correct and message to error
			$correct{'lastName'} = "";
			$errors{'lastName'} = "<tr><td></td><td><font color=\"red\" size=\"2\">Invalid Last Name Given</font></td></tr>";
		}
		
		#username
		if($validUserName == 1){
			
			#add value to correct and blank to error
			$correct{'username'} = $user_info{'username'};
			$errors{'username'} = "";
		}
		else{
			
			#add blank to correct and message to error
			$correct{'username'} = "";
			$errors{'username'} = "<tr><td></td><td><font color=\"red\" size=\"2\">Invalid or already taken Username Given</font></td></tr>";
		}
		
		#email
		if($validEmail == 1){
			
			#add value to correct and blank to error
			$correct{'email'} = $user_info{'email'};
			$errors{'email'} = "";
		}
		else{
			
			#add blank to correct and message to error
			$correct{'email'} = "";
			$errors{'email'} = "<tr><td></td><td><font color=\"red\" size=\"2\">Invalid Email Given</font></td></tr>";
		}
		
		#password is handled differently as that will not be re-displayed
		if($validPwords == 0){
			
			#only display error if invalid
			$errors{'password'} = "<tr><td></td><td><font color=\"red\" size=\"2\">Passwords were empty or didnt match</font></td></tr>";
			
		}
		
		#now that the individual errors were determined, call the subroutine to re-display the form and pass it the proper values and error messages
		#declare error message
		my $main_error_message = "<h4><font color=\"red\">Some information was incorrectly entered. <br>Please see the individual fields for details and try again.</font></h4>";
		display_registration($main_error_message, \%errors, \%correct);
	}
	
}

#subroutine to send confirmation emails to the newly registered users
sub send_confirmation{
	
	#obtain user information from parameter
	my $ref_user_info = $_[0];
	
	#dereference hash
	my %user_info = %$ref_user_info;
	
	#proceed to use sendmail to send infomration to user
	#open mailhandle
	open(MAIL, "|/usr/sbin/sendmail -t");
	
	#send information to the mailhandler
	#start by sending the email header
	print MAIL "To: $user_info{'email'}\n";
	print MAIL "From: tr2286\@columbia.edu\n";
	print MAIL "Subject: Thank You for Registering\n\n";

	#now send the testmessage
	print MAIL "Dear $user_info{'firstName'},\n\nThank you for registering with this file management system. The information you provided was:\n\n";
	print MAIL "First Name: $user_info{'firstName'}\n";
	print MAIL "Last Name: $user_info{'lastName'}\n";
	print MAIL "Username: $user_info{'username'}\n";
	print MAIL "Email: $user_info{'email'}\n\n";
	print MAIL "We hope you enjoy this service!\n\n\nBest Regards,\n\nNathaniel Clinger and Thomas Rantasa";

	#cose the mailhandle
	close(MAIL);
}

#subroutine to set the necessary user information in teh info table
#this will be used to display the general information about a user
#this is passed the username as a parameter
sub add_information_to_db{
	
	#get parameter
	my $user_name = $_[0];
	
	#do not add most common words or avg doc size because that will be determined whenever files are added
	#set number of files and users to 0 so that they just have to be incremented by other methods
	
	DBQueries::addInfo( $user_name, "fileCount", 0);
}

#subroutine that is called whenever the user succesfully submits his/her data
#this subroutine will display a success message to the user before redirecting to the main window
#this sub is passed two parameters, the users first name and the username
sub show_success{
	
	#obtain parameter
	my $username = $_[0];
	
	#call method to display html beginnign
	HTMLSubs->generate_html_beginning("Successfully Created Account!");
	
	#call sub to print header
	HTMLSubs -> generate_display_head("Document Management System", "Account Created Successfully", $username);
	
	print <<END_HTML;
	
	<!--now display the message to the user-->
	<h4>You can manage your new account in your profile.</h4>
	<br>
	
END_HTML

	#create hash for button
	my %username_hash;
	$username_hash{'username'} = $username;
	
	#call subroutine to display button that returns the user to the profile
	HTMLSubs -> generate_html_button("profile.pl.cgi", "Go To profile", \%username_hash);

	#now call method to produce closing html tags
	HTMLSubs->generate_html_end();
}

#subroutine to display the full user-registration site
#this subroutine takes three potential parameters, one which is an error message or any text to be displayed above the form
#and the other is an array of error messages associated with individual fields
#and the last one is a hash of previously entered correct values
sub display_registration{
	
	#obtain potential messages
	my $error_text = $_[0];
	
	#obtain errors
	my $ref_individual_errors = $_[1] || "";
	
	#dereference or create empty hash if no reference exits
	my %individual_errors;
	#check if refernce is empty
	if(length($ref_individual_errors) == 0){
		
		#in this case create an empty hash
		%individual_errors = {};
	}
	#otherwise use reference
	else{
		%individual_errors = %$ref_individual_errors;
	}
	
	#obtain potential correct entries to re-display in form
	my $ref_correct_entries = $_[2] || "";
	
	#dereference or create empty hash if no reference exits
	my %correct_entries;
	
	#check if refernce is empty
	if(length($ref_correct_entries) == 0){
		
		#in this case create an empty hash
		%correct_entries = {};
	}
	#otherwise use reference
	else{
		%correct_entries = %$ref_correct_entries;
	}
	
	#start by calling the subroutine from the module to generate the beginning html code
	HTMLSubs->generate_html_beginning("User Registration");
	
	#next call internal subroutine to generate the html code for the registration from
	#this form will be targeted back to the same script so pass the name as a parameter
	generate_registration_html($ENV{'SCRIPT_NAME'}, $ref_individual_errors, $ref_correct_entries);
	
	#lastly call subroutine to print the closing html tags
	HTMLSubs->generate_html_end();
}

#subroutine to create the html registration form
#this sub is passed the name of the target for the form
#also, this sub is passed an array of individual error messages associated with possible incorrect previous submissions
sub generate_registration_html{
	
	#obtain target
	my $form_target = $_[0];
	
	#obtain errors
	my $ref_individual_errors = $_[1] || "";
	
	#dereference or create empty hash if no reference exits
	my %individual_errors;
	
	#check if refernce is empty
	if(length($ref_individual_errors) == 0){
		
		#in this case create an empty hash
		%individual_errors = {};
	}
	#otherwise use reference
	else{
		%individual_errors = %$ref_individual_errors;
	}
	
	#obtain potential correct entries to re-display in form
	my $ref_correct_entries = $_[2] || "";
	
	#dereference or create empty hash if no reference exits
	my %correct_entries;
	
	#check if refernce is empty
	if(length($ref_correct_entries) == 0){
		
		#in this case create an empty hash
		%correct_entries = {};
	}
	#otherwise use reference
	else{
		%correct_entries = %$ref_correct_entries;
	}
	
	#now print the hmtl code
	print <<END_HTML;
	
	<div class="header">
	<div class="titles">
	<h1>Document Management System</h1>
	</div>
	
	<!--titles-->
	<h2>Register</h2>
	<h3>You are not logged in</h3>
	
	<table class="tableheader">
	<tr class="trheader">
	<td class="tdheaderleft"></td>
	<td class="tdheaderright"></td>
	
	</tr>
	</table>
	</div><!-- end of header of the profile header-->
	
	<!-- place form in table for appearance formatting-->
	<!-- individual error messages are displayed below the designated fields if those messages are not intentionally left blank-->
		<table>
			<form action="$form_target" method=POST>
			<tr>
				<!-- first name-->
				<td><p>First Name:*</p></td>
				<td><input type="text" name="firstName" value="$correct_entries{'firstName'}"></td>
			</tr>
			$individual_errors{'firstName'}
			<tr>
				<!-- last name-->
				<td><p>Last Name:*</p></td>
				<td><input type="text" name="lastName" value="$correct_entries{'lastName'}"></td>
			</tr>
			$individual_errors{'lastName'}
			<tr>
				<!-- username-->
				<td><p>Username:*</p></td>
				<td><input type="text" name="username" value="$correct_entries{'username'}"></td>
			</tr>
			$individual_errors{'username'}
			<tr>
				<!-- email-->
				<td><p>Email:*</p></td>
				<td><input type="text" name="email" value="$correct_entries{'email'}"></td>
			</tr>
			$individual_errors{'email'}
			<tr>
				<!-- password-->
				<td><p>Password:*</p></td>
				<td><input type="password" name="password1"></td>
			</tr>
			$individual_errors{'password'}
			<tr>
				<!-- password repeat-->
				<td><p>Repeat<br>Password:*</p></td>
				<td><input type="password" name="password2"></td>
			</tr>
			<tr>
				<!-- submit button-->
				<td><input type="submit" value="Submit"></form>
END_HTML

		#create cancel button
		#declare empty hash
		my %parameter_hash = ();
		#call subroutine to crate a cancel button
		#this button will link back to login
		HTMLSubs -> generate_html_button("login.pl.cgi", "Cancel", \%parameter_hash);
		
		#print remaining tags
		print <<END_HTML;
			</td>
			</tr>
		</table>
END_HTML

}

#subroutine to obtain and determine what information is passed to the script
#to make this more universal, both GET and POST methods are accepted 
#this reads input for both GET and POST
sub obtain_input{

	#declare scalar to hold passed information
	my $input;

	#now retrieve the input through either get or post
	#change the case of request method
	$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;

	#if post use STDIN
	if ($ENV{'REQUEST_METHOD'} eq "POST"){
		read(STDIN, $input, $ENV{'CONTENT_LENGTH'});

		#exchange plus signs to spaces
		$input =~ s/\+/ /;

		#deal with special characters using the substitution sample provided
		$input =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
	}
	#otherwise the env hash
	else{
		$input = $ENV{'QUERY_STRING'};
		
		#exchange plus signs to spaces
		$input =~ s/\+/ /;
		
		#deal with special characters using the substitution sample provided
		$input =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
	}
	
	#now return the correct input
	return $input;	
}